
#include "session.h"

#ifndef CONFIG_MEDIA_EMULATE_ON_PC
#include <asm/shdev.h>
#include <asm/delay.h>
#endif

#include <uapi/stdlib.h>
#include <uapi/string.h>

#ifndef CONFIG_MEDIA_EMULATE_ON_PC
#include <asm/dispapi.h>
#include <arch_irq.h>
#endif

//////////////////////////////////////////////////////////////////////////////////////////////
//
#define BASIC_PAGE_SIZE 4096

#define EDMA_CHN_IO 2
#define EDMA_CHN_MEDIA 3

// all SB unit size must more than DATBUF_MAX_BUF_CNT
#define BASIC_SB_COUNT 32

//////////////////////////////////////////////////////////////////////////////////////////////

/**
*  debug
*/

int null_debug(const char *fmt, ...)
{
	return 0;
}

/**
 * SB list function
 */

static session_buffer_t sb_list[BASIC_SB_COUNT];

static void SessionSbInit(void)
{
	memset(sb_list, 0, sizeof(sb_list));
}

static session_buffer_t *SessionSbAlloc(psysbuf_t buf)
{
	int i;
	uint32_t flags;
	session_buffer_t *sb;

	if (buf == NULL)
		return NULL;

	local_irq_save(flags);

	for (i = 0; i < BASIC_SB_COUNT; i++)
	{
		sb = &sb_list[i];
		if (sb->buf == NULL) {
			sb->buf = buf;
			break;
		}
		sb = NULL;
	}

	local_irq_restore(flags);

	return sb;
}

static psysbuf_t SessionSbSwitchFree(session_buffer_t *sb)
{
	uint32_t flags;
	psysbuf_t buf = NULL;

	if (sb == NULL)
		return NULL;

	local_irq_save(flags);

	buf = sb->buf;
	sb->buf = NULL;

	local_irq_restore(flags);

	return buf;

}

//////////////////////////////////////////////////////////////////////////////////////////////

void SessionBufferInit(struct SESSION *session)
{
	if (session == NULL)
		return;

	slists_group_init(&session->buffer_group);
}

static session_buffer_t *SessionBufferPush_(struct SESSION *session, psysbuf_t buf)
{
	session_buffer_t *sb;
	if (session == NULL || buf == NULL)
		return NULL;

	sb = SessionSbAlloc(buf);
	if (sb != NULL) {
		slists_init(&(sb->list));
		sb->list.group = &session->buffer_group;
		slists_put(&(sb->list));
	}

	return sb;
}

session_buffer_t *SessionBufferPush(struct SESSION *session, psysbuf_t buf)
{
	session_buffer_t *sb = SessionBufferPush_(session, buf);
	if (sb != NULL) {
		SessionCommand(session, SSCMD_STREAM_BUFCHANGED, sb);
	}
	return sb;
}

psysbuf_t SessionBufferPop(struct SESSION *session)
{
	psysbuf_t buf = NULL;
	session_buffer_t *sb;
	if (session == NULL)
		return NULL;
	sb = (session_buffer_t *)slists_get(&session->buffer_group);
	if (sb) {
		buf = SessionSbSwitchFree(sb);
	}
	return buf;
}

psysbuf_t SessionBufferTop(struct SESSION *session)
{
	psysbuf_t buf = NULL;
	session_buffer_t *sb;
	if (session == NULL)
		return NULL;
	sb = (session_buffer_t *)slists_chktop(&session->buffer_group);
	if (sb) {
		buf = sb->buf;
	}
	return buf;
}

int SessionBufferTopNum(struct SESSION *session)
{
	if (session == NULL)
		return 0;
	return slists_topnum(&session->buffer_group);
}

void SessionBufferDeInit(struct SESSION *session)
{
	psysbuf_t buf = NULL;
	if (session == NULL)
		return;

	do {
		buf = SessionBufferPop(session);
		if (buf) {
			sysbuf_free(buf);
		}
	} while (buf != NULL);

	slists_group_init(&session->buffer_group);

}

/*

static
SESSIONSTATE SESSIONAPI(SessionRun)(struct SESSION *session,SESSIONHANDLE handle)
{
	return SSTATE_NULL;
}

static
int SESSIONAPI(SessionCommand)(struct SESSION *session,SESSIONHANDLE handle,int cmd, void *params)
{
	return 0;
}

static
void SESSIONAPI(SessionDeInit)(struct SESSION *session,SESSIONHANDLE handle)
{

}

static
SESSIONHANDLE SESSIONAPI(SessionInit)(struct SESSION *session)
{
	return NULL;
}
*/

///////////////////////////////////////////////////////////////////////////////////////////////
static const struct SESSION *gSessions_null[] = { NULL, NULL, };
static const struct SESSION **gSessions_all = (const struct SESSION **)gSessions_null;

void SessionInitAll(const struct SESSION *gSessions[])
{
	int index;
	struct SESSION *session;
	SESSIONHANDLE handle;

	/* data init */
	SessionSbInit();

	/* Set */
	gSessions_all = (const struct SESSION **)gSessions;

	/* init */
	index = 0;
	while (gSessions_all[index] != NULL) {
		session = (struct SESSION *)gSessions_all[index];
		handle = session->SessionInit(session);
		if (handle == NULL) {
			debug("\tFailed !");
		}
		index++;
	}
}


void SessionDeInitAll(void)
{
	int index;
	struct SESSION *session;

	index = 0;
	while (gSessions_all[index] != NULL) {
		session = (struct SESSION *)gSessions_all[index];
		session->SessionDeInit(session);
		index++;
	}
}

struct SESSION *SessionGet(session_type_t type)
{
	int index;
	struct SESSION *session;
	if (type >= SST_TYPES)
		return NULL;

	index = 0;
	session = NULL;
	while (gSessions_all[index] != NULL) {
		session = (struct SESSION *)gSessions_all[index];
		if (session->types & (1 << ((int)type)))
			break;
		index++;
		session = NULL;
	}

	return session;
}

struct SESSION *SessionNext(struct SESSION *session)
{
	int index;
	if (session == NULL)
		return (struct SESSION *)gSessions_all[0];

	index = 0;
	while (gSessions_all[index] != NULL) {
		if (gSessions_all[index] == session)
			break;
		index++;
	}

	if (gSessions_all[index] == session)
		return (struct SESSION *)gSessions_all[index + 1];

	return NULL;
}

SESSIONSTATE SessionRun(struct SESSION *session)
{
	int index;
	if (session == NULL)
		return -EINVAL;

	index = 0;
	while (gSessions_all[index] != NULL) {
		if (session == gSessions_all[index])
			break;
		index++;
	}

	if (gSessions_all[index] == NULL)
		return -EACCES;

	return session->SessionRun(session);
}

int SessionCommand(struct SESSION *session, int cmd, void *params)
{
	int index;
	if (session == NULL)
		return -EINVAL;

	index = 0;
	while (gSessions_all[index] != NULL) {
		if (session == gSessions_all[index])
			break;
		index++;
	}

	if (gSessions_all[index] == NULL)
		return -EACCES;

	return session->SessionCommand(session, cmd, params);
}

